break;
case MMUEXT_INVLPG_LOCAL:
- __flush_tlb_one(op.linear_addr);
+ local_flush_tlb_one(op.linear_addr);
break;
case MMUEXT_TLB_FLUSH_MULTI:
- flush_tlb_mask(d->cpuset); /* XXX KAF XXX */
- break;
-
case MMUEXT_INVLPG_MULTI:
- flush_tlb_mask(d->cpuset); /* XXX KAF XXX */
+ {
+ unsigned long inset = op.cpuset, outset = 0;
+ while ( inset != 0 )
+ {
+ unsigned int vcpu = find_first_set_bit(inset);
+ inset &= ~(1UL<<vcpu);
+ if ( (vcpu < MAX_VIRT_CPUS) &&
+ ((ed = d->exec_domain[vcpu]) != NULL) )
+ outset |= 1UL << ed->processor;
+ }
+ if ( op.cmd == MMUEXT_TLB_FLUSH_MULTI )
+ flush_tlb_mask(outset & d->cpuset);
+ else
+ flush_tlb_one_mask(outset & d->cpuset, op.linear_addr);
break;
+ }
case MMUEXT_TLB_FLUSH_ALL:
flush_tlb_mask(d->cpuset);
break;
case MMUEXT_INVLPG_ALL:
- flush_tlb_mask(d->cpuset); /* XXX KAF XXX */
+ flush_tlb_one_mask(d->cpuset, op.linear_addr);
break;
case MMUEXT_FLUSH_CACHE:
percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
break;
case UVMF_INVLPG_LOCAL:
- __flush_tlb_one(va);
+ local_flush_tlb_one(va);
break;
case UVMF_INVLPG_ALL:
- flush_tlb_mask(d->cpuset); /* XXX KAF XXX */
+ flush_tlb_one_mask(d->cpuset, va);
break;
}
/* Ensure that there are no stale writable mappings in any TLB. */
/* NB. INVLPG is a serialising instruction: flushes pending updates. */
- __flush_tlb_one(l1va); /* XXX Multi-CPU guests? */
+ local_flush_tlb_one(l1va); /* XXX Multi-CPU guests? */
PTWR_PRINTK("[%c] disconnected_l1va at %p now %p\n",
PTWR_PRINT_WHICH, ptep, pte);
likely(!shadow_mode_enabled(ed->domain)) )
{
*pl2e = mk_l2_pgentry(l2e & ~_PAGE_PRESENT);
- flush_tlb(); /* XXX Multi-CPU guests? */
+ local_flush_tlb(); /* XXX Multi-CPU guests? */
}
/* Temporarily map the L1 page, and make a copy of it. */
}
/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
- __flush_tlb();
+ local_flush_tlb();
/* Save MTRR state */
rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
static void post_set(void)
{
/* Flush TLBs (no need to flush caches - they are disabled) */
- __flush_tlb();
+ local_flush_tlb();
/* Intel (P6) standard MTRRs */
wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
}
static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long flush_cpumask;
+static unsigned long flush_cpumask, flush_va;
asmlinkage void smp_invalidate_interrupt(void)
{
ack_APIC_irq();
perfc_incrc(ipis);
- local_flush_tlb();
+ if ( flush_va == FLUSHVA_ALL )
+ local_flush_tlb();
+ else
+ local_flush_tlb_one(flush_va);
clear_bit(smp_processor_id(), &flush_cpumask);
}
-void flush_tlb_mask(unsigned long mask)
+void __flush_tlb_mask(unsigned long mask, unsigned long va)
{
ASSERT(local_irq_is_enabled());
{
spin_lock(&flush_lock);
flush_cpumask = mask;
+ flush_va = va;
send_IPI_mask(mask, INVALIDATE_TLB_VECTOR);
while ( flush_cpumask != 0 )
cpu_relax();
spin_lock(&flush_lock);
flush_cpumask = (1UL << smp_num_cpus) - 1;
flush_cpumask &= ~(1UL << smp_processor_id());
+ flush_va = FLUSHVA_ALL;
send_IPI_allbutself(INVALIDATE_TLB_VECTOR);
while ( flush_cpumask != 0 )
cpu_relax();
static void flush_tlb_all_pge_ipi(void *info)
{
- __flush_tlb_pge();
+ local_flush_tlb_pge();
}
void flush_tlb_all_pge(void)
{
smp_call_function(flush_tlb_all_pge_ipi, 0, 1, 1);
- __flush_tlb_pge();
+ local_flush_tlb_pge();
}
void smp_send_event_check_mask(unsigned long cpu_mask)
{
/* Super-page mapping. */
if ( (l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
- __flush_tlb_pge();
+ local_flush_tlb_pge();
*pl2e = mk_l2_pgentry(p|flags|_PAGE_PSE);
v += 1 << L2_PAGETABLE_SHIFT;
}
pl1e = l2_pgentry_to_l1(*pl2e) + l1_table_offset(v);
if ( (l1_pgentry_val(*pl1e) & _PAGE_PRESENT) )
- __flush_tlb_one(v);
+ local_flush_tlb_one(v);
*pl1e = mk_l1_pgentry(p|flags);
v += 1 << L1_PAGETABLE_SHIFT;
{
/* Super-page mapping. */
if ( (l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
- __flush_tlb_pge();
+ local_flush_tlb_pge();
*pl2e = mk_l2_pgentry(p|flags|_PAGE_PSE);
v += 1 << L2_PAGETABLE_SHIFT;
}
pl1e = l2_pgentry_to_l1(*pl2e) + l1_table_offset(v);
if ( (l1_pgentry_val(*pl1e) & _PAGE_PRESENT) )
- __flush_tlb_one(v);
+ local_flush_tlb_one(v);
*pl1e = mk_l1_pgentry(p|flags);
v += 1 << L1_PAGETABLE_SHIFT;
if ( ((host_virt_addr != 0) || (flags & GNTMAP_host_map) ) &&
unlikely(!__addr_ok(host_virt_addr)))
{
- DPRINTK("Bad virtual address (%x) or flags (%x).\n", host_virt_addr, flags);
+ DPRINTK("Bad virtual address (%x) or flags (%x).\n",
+ host_virt_addr, flags);
(void)__put_user(GNTST_bad_virt_addr, &uop->handle);
return GNTST_bad_gntref;
}
*/
}
- /* Only make the maptrack live _after_ writing the pte, in case
- * we overwrite the same frame number, causing a maptrack walk to find it */
+ /*
+ * Only make the maptrack live _after_ writing the pte, in case we
+ * overwrite the same frame number, causing a maptrack walk to find it.
+ */
ld->grant_table->maptrack[handle].domid = dom;
ld->grant_table->maptrack[handle].ref_and_flags =
(ref << MAPTRACK_REF_SHIFT) | (flags & MAPTRACK_GNTMAP_MASK);
unsigned long va = 0;
for ( i = 0; i < count; i++ )
- if ( __gnttab_map_grant_ref(&uop[i], &va) == 0)
+ if ( __gnttab_map_grant_ref(&uop[i], &va) == 0 )
flush++;
+ /* XXX KAF: I think we are probably flushing too much here. */
if ( flush == 1 )
- __flush_tlb_one(va);
+ flush_tlb_one_mask(current->domain->cpuset, va);
else if ( flush != 0 )
- local_flush_tlb();
+ flush_tlb_mask(current->domain->cpuset);
return 0;
}
unsigned long _ol1e;
pl1e = &linear_pg_table[l1_linear_offset(virt)];
-
+
if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
{
DPRINTK("Could not find PTE entry for address %x\n", virt);
unsigned long va = 0;
for ( i = 0; i < count; i++ )
- if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0)
+ if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 )
flush++;
if ( flush == 1 )
- __flush_tlb_one(va);
-
+ flush_tlb_one_mask(current->domain->cpuset, va);
else if ( flush != 0 )
- local_flush_tlb();
+ flush_tlb_mask(current->domain->cpuset);
return 0;
}
/* Write pagetable base and implicitly tick the tlbflush clock. */
extern void write_cr3(unsigned long cr3);
-/*
- * TLB flushing:
- *
- * - flush_tlb() flushes the current mm struct TLBs
- * - flush_tlb_all() flushes all processes TLBs
- * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
- *
- * ..but the i386 has somewhat limited tlb flushing capabilities,
- * and page-granular flushes are available only on i486 and up.
- */
-
-#define __flush_tlb() \
+#define local_flush_tlb() \
do { \
unsigned long cr3 = read_cr3(); \
write_cr3(cr3); \
} while ( 0 )
-#ifndef CONFIG_SMP
+#define local_flush_tlb_pge() \
+ do { \
+ __pge_off(); \
+ local_flush_tlb(); \
+ __pge_on(); \
+ } while ( 0 )
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() __flush_tlb()
-#define flush_tlb_all_pge() __flush_tlb_pge()
-#define local_flush_tlb() __flush_tlb()
-#define flush_tlb_cpu(_cpu) __flush_tlb()
-#define flush_tlb_mask(_mask) __flush_tlb()
-#define try_flush_tlb_mask(_mask) __flush_tlb()
+#define local_flush_tlb_one(__addr) \
+ __asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
-#else
+#define flush_tlb_all() flush_tlb_mask((1 << smp_num_cpus) - 1)
+#ifndef CONFIG_SMP
+#define flush_tlb_all_pge() local_flush_tlb_pge()
+#define flush_tlb_mask(_mask) local_flush_tlb()
+#define flush_tlb_one_mask(_mask,_v) local_flush_tlb_one(_v)
+#else
#include <xen/smp.h>
-
-extern int try_flush_tlb_mask(unsigned long mask);
-extern void flush_tlb_mask(unsigned long mask);
+#define FLUSHVA_ALL (~0UL)
extern void flush_tlb_all_pge(void);
-
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() flush_tlb_mask((1 << smp_num_cpus) - 1)
-#define local_flush_tlb() __flush_tlb()
-#define flush_tlb_cpu(_cpu) flush_tlb_mask(1 << (_cpu))
-
+extern void __flush_tlb_mask(unsigned long mask, unsigned long va);
+#define flush_tlb_mask(_mask) __flush_tlb_mask(_mask,FLUSHVA_ALL)
+#define flush_tlb_one_mask(_mask,_v) __flush_tlb_mask(_mask,_v)
#endif
#endif /* __FLUSHTLB_H__ */
extern void paging_init(void);
-/* Flush global pages as well. */
-
#define __pge_off() \
do { \
__asm__ __volatile__( \
: : "r" (mmu_cr4_features) ); \
} while ( 0 )
-
-#define __flush_tlb_pge() \
- do { \
- __pge_off(); \
- __flush_tlb(); \
- __pge_on(); \
- } while ( 0 )
-
-#define __flush_tlb_one(__addr) \
- __asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
-
#endif /* !__ASSEMBLY__ */